diff -urdN linux-5.16.11/Documentation/lzip.txt linux-5.16.11.new/Documentation/lzip.txt
--- linux-5.16.11/Documentation/lzip.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/Documentation/lzip.txt	2022-02-28 22:10:45.790400069 +0100
@@ -0,0 +1,58 @@
+==============================
+Lzip data compression in Linux
+==============================
+
+Introduction
+============
+
+Lzip is a lossless data compressor with a user interface similar to the one
+of gzip or bzip2. Lzip uses a simplified form of the 'Lempel-Ziv-Markov
+chain-Algorithm' (LZMA) stream format, chosen to maximize safety and
+interoperability. Lzip can compress about as fast as gzip (lzip -0) or
+compress most files more than bzip2 (lzip -9). Decompression speed is
+intermediate between gzip and bzip2. Lzip is better than gzip and bzip2 from
+a data recovery perspective. Lzip has been designed, written, and tested
+with great care to replace gzip and bzip2 as the standard general-purpose
+compressed format for unix-like systems, especially for long-term archiving.
+
+Learn more about lzip at http://www.nongnu.org/lzip/lzip.html
+
+Lzip related components in the kernel
+=====================================
+
+The lzip_decompress module in lib/lzip_decompress.c provides a versatile lzip
+decompression function able to do buffer to buffer decompression or stream
+decompression with fill and flush callback functions. The usage of the
+function is documented in include/linux/lzip.h.
+
+For decompressing the kernel image, initramfs, and initrd, there is a wrapper
+function in lib/decompress_lunzip.c providing the same common interface as the
+other decompress_*.c files, which is defined in
+include/linux/decompress/generic.h.
+
+For kernel makefiles, two commands are provided in scripts/Makefile.lib for
+use with $(call if_changed). The kernel image must be compressed with
+$(call if_changed,klzip) which will append a four-byte trailer containing the
+size of the uncompressed data needed by the boot code. Other things should be
+compressed with $(call if_changed,lzip).
+
+Testing
+=======
+
+Lzip-compressed kernel images of multiple linux versions since 2.6.30.10 have
+been built and tested, even on machines as modest as an AMD 486-DX2 at 66 MHz
+with 64 MiB of RAM. In the worst case (on the slow machine above), lzip just
+increased the boot time a 15% compared with gzip. On more modern machines,
+lzip may boot slightly faster than gzip. It just takes 0.2 seconds for lzip to
+decompress vmlinuz-4.4.16 on my machine.
+
+Decompression time is usually a small fraction of the total boot time. For
+example, using lz4 on a desktop machine in order to save 0.05 seconds of a
+total boot time of 20 seconds is probably not worth the increased image size.
+
+Xlunzip is a test tool for the lzip_decompress module. It is similar to
+lunzip, but it uses the lzip_decompress module as a backend. The xlunzip home
+page is at http://www.nongnu.org/lzip/xlunzip.html
+
+Author: Antonio Diaz Diaz
+Updated: 2021-03-22
diff -urdN linux-5.16.11/Makefile linux-5.16.11.new/Makefile
--- linux-5.16.11/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/Makefile	2022-02-28 22:22:19.180431558 +0100
@@ -474,6 +474,7 @@
 BASH		= bash
 KGZIP		= gzip
 KBZIP2		= bzip2
+KLZIP		= lzip
 KLZOP		= lzop
 LZMA		= lzma
 LZ4		= lz4c
@@ -528,7 +529,7 @@
 export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
 export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
 export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
-export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
+export KGZIP KBZIP2 KLZIP KLZOP LZMA LZ4 XZ ZSTD
 export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
 
 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
diff -urdN linux-5.16.11/arch/arm/Kconfig linux-5.16.11.new/arch/arm/Kconfig
--- linux-5.16.11/arch/arm/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/arm/Kconfig	2022-02-28 22:10:45.790400069 +0100
@@ -98,6 +98,7 @@
 	select HAVE_IRQ_TIME_ACCOUNTING
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZ4
+	select HAVE_KERNEL_LZIP
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_XZ
diff -urdN linux-5.16.11/arch/arm/boot/compressed/Makefile linux-5.16.11.new/arch/arm/boot/compressed/Makefile
--- linux-5.16.11/arch/arm/boot/compressed/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/arm/boot/compressed/Makefile	2022-02-28 22:10:45.790400069 +0100
@@ -77,6 +77,7 @@
 CPPFLAGS_vmlinux.lds += -DMALLOC_SIZE="$(MALLOC_SIZE)"
 
 compress-$(CONFIG_KERNEL_GZIP) = gzip
+compress-$(CONFIG_KERNEL_LZIP) = klzip
 compress-$(CONFIG_KERNEL_LZO)  = lzo
 compress-$(CONFIG_KERNEL_LZMA) = lzma
 compress-$(CONFIG_KERNEL_XZ)   = xzkern
diff -urdN linux-5.16.11/arch/arm/boot/compressed/decompress.c linux-5.16.11.new/arch/arm/boot/compressed/decompress.c
--- linux-5.16.11/arch/arm/boot/compressed/decompress.c	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/arm/boot/compressed/decompress.c	2022-02-28 22:10:45.790400069 +0100
@@ -38,6 +38,10 @@
 #include "../../../../lib/decompress_inflate.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZIP
+#include "../../../../lib/decompress_lunzip.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZO
 #include "../../../../lib/decompress_unlzo.c"
 #endif
diff -urdN linux-5.16.11/arch/x86/Kconfig linux-5.16.11.new/arch/x86/Kconfig
--- linux-5.16.11/arch/x86/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/x86/Kconfig	2022-02-28 22:10:45.790400069 +0100
@@ -211,6 +211,7 @@
 	select HAVE_KERNEL_BZIP2
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZ4
+	select HAVE_KERNEL_LZIP
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_XZ
diff -urdN linux-5.16.11/arch/x86/boot/compressed/Makefile linux-5.16.11.new/arch/x86/boot/compressed/Makefile
--- linux-5.16.11/arch/x86/boot/compressed/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/x86/boot/compressed/Makefile	2022-02-28 22:10:45.790400069 +0100
@@ -26,6 +26,7 @@
 KCOV_INSTRUMENT		:= n
 
 targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
+	vmlinux.bin.lz \
 	vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 vmlinux.bin.zst
 
 # CLANG_FLAGS must come before any cc-disable-warning or cc-option calls in
@@ -127,6 +128,8 @@
 	$(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz: $(vmlinux.bin.all-y) FORCE
+	$(call if_changed,klzip)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
 	$(call if_changed,lzma)
 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
@@ -140,6 +143,7 @@
 
 suffix-$(CONFIG_KERNEL_GZIP)	:= gz
 suffix-$(CONFIG_KERNEL_BZIP2)	:= bz2
+suffix-$(CONFIG_KERNEL_LZIP)	:= lz
 suffix-$(CONFIG_KERNEL_LZMA)	:= lzma
 suffix-$(CONFIG_KERNEL_XZ)	:= xz
 suffix-$(CONFIG_KERNEL_LZO) 	:= lzo
diff -urdN linux-5.16.11/arch/x86/boot/compressed/misc.c linux-5.16.11.new/arch/x86/boot/compressed/misc.c
--- linux-5.16.11/arch/x86/boot/compressed/misc.c	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/arch/x86/boot/compressed/misc.c	2022-02-28 22:10:45.790400069 +0100
@@ -62,6 +62,10 @@
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZIP
+#include "../../../../lib/decompress_lunzip.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
diff -urdN linux-5.16.11/fs/squashfs/Kconfig linux-5.16.11.new/fs/squashfs/Kconfig
--- linux-5.16.11/fs/squashfs/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/Kconfig	2022-02-28 22:10:45.790400069 +0100
@@ -136,6 +136,21 @@
 
 	  If unsure, say N.
 
+config SQUASHFS_LZIP
+	bool "Include support for LZIP compressed file systems"
+	depends on SQUASHFS
+	select LZIP_DECOMPRESS
+	help
+	  Saying Y here includes support for reading Squashfs file systems
+	  compressed with LZIP compression.  LZIP gives better compression
+	  than the default zlib compression, at the expense of greater CPU
+	  and memory overhead.
+
+	  LZIP is not the standard compression used in Squashfs and so most
+	  file systems will be readable without selecting this option.
+
+	  If unsure, say N.
+
 config SQUASHFS_LZO
 	bool "Include support for LZO compressed file systems"
 	depends on SQUASHFS
diff -urdN linux-5.16.11/fs/squashfs/Makefile linux-5.16.11.new/fs/squashfs/Makefile
--- linux-5.16.11/fs/squashfs/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/Makefile	2022-02-28 22:10:45.790400069 +0100
@@ -13,6 +13,7 @@
 squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o
 squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
 squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o
+squashfs-$(CONFIG_SQUASHFS_LZIP) += lzip_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
 squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o
diff -urdN linux-5.16.11/fs/squashfs/decompressor.c linux-5.16.11.new/fs/squashfs/decompressor.c
--- linux-5.16.11/fs/squashfs/decompressor.c	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/decompressor.c	2022-02-28 22:10:45.790400069 +0100
@@ -34,6 +34,12 @@
 };
 #endif
 
+#ifndef CONFIG_SQUASHFS_LZIP
+static const struct squashfs_decompressor squashfs_lzip_comp_ops = {
+	NULL, NULL, NULL, NULL, LZIP_COMPRESSION, "lzip", 0
+};
+#endif
+
 #ifndef CONFIG_SQUASHFS_LZO
 static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
 	NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
@@ -65,6 +71,7 @@
 static const struct squashfs_decompressor *decompressor[] = {
 	&squashfs_zlib_comp_ops,
 	&squashfs_lz4_comp_ops,
+	&squashfs_lzip_comp_ops,
 	&squashfs_lzo_comp_ops,
 	&squashfs_xz_comp_ops,
 	&squashfs_lzma_unsupported_comp_ops,
diff -urdN linux-5.16.11/fs/squashfs/decompressor.h linux-5.16.11.new/fs/squashfs/decompressor.h
--- linux-5.16.11/fs/squashfs/decompressor.h	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/decompressor.h	2022-02-28 22:10:45.790400069 +0100
@@ -38,6 +38,10 @@
 extern const struct squashfs_decompressor squashfs_lz4_comp_ops;
 #endif
 
+#ifdef CONFIG_SQUASHFS_LZIP
+extern const struct squashfs_decompressor squashfs_lzip_comp_ops;
+#endif
+
 #ifdef CONFIG_SQUASHFS_LZO
 extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
 #endif
diff -urdN linux-5.16.11/fs/squashfs/lzip_wrapper.c linux-5.16.11.new/fs/squashfs/lzip_wrapper.c
--- linux-5.16.11/fs/squashfs/lzip_wrapper.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/lzip_wrapper.c	2022-02-28 23:14:30.780431657 +0100
@@ -0,0 +1,129 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2014
+ * Phillip Lougher <phillip@squashfs.org.uk>
+ * Copyright (C) 2018-2022 Antonio Diaz Diaz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * lzip_wrapper.c
+ */
+
+#include <linux/bio.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/lzip.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs.h"
+#include "decompressor.h"
+#include "page_actor.h"
+
+struct squashfs_lzip {
+	void *input;
+	void *output;
+};
+
+
+static void *lzip_init(struct squashfs_sb_info *msblk, void *buff)
+{
+	int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
+	struct squashfs_lzip *stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (stream == NULL)
+		goto failed;
+	stream->input = vmalloc(block_size);
+	if (stream->input == NULL)
+		goto failed2;
+	stream->output = vmalloc(block_size);
+	if (stream->output != NULL)
+		return stream;
+
+	vfree(stream->input);
+failed2:
+	kfree(stream);
+failed:
+	ERROR("Failed to initialise LZIP decompressor\n");
+	return ERR_PTR(-ENOMEM);
+}
+
+
+static void lzip_free(void *strm)
+{
+	struct squashfs_lzip *stream = strm;
+
+	if (stream) {
+		vfree(stream->input);
+		vfree(stream->output);
+	}
+	kfree(stream);
+}
+
+
+static int lzip_uncompress(struct squashfs_sb_info *msblk, void *strm,
+	struct bio *bio, int offset, int length,
+	struct squashfs_page_actor *output)
+{
+	struct bvec_iter_all iter_all = {};
+	struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
+	struct squashfs_lzip *stream = strm;
+	void *buff = stream->input, *data;
+	long out_pos;
+	int bytes = length, res;
+
+	while (bio_next_segment(bio, &iter_all)) {
+		int avail = min(bytes, ((int)bvec->bv_len) - offset);
+
+		data = bvec_virt(bvec);
+		memcpy(buff, data + offset, avail);
+		buff += avail;
+		bytes -= avail;
+		offset = 0;
+	}
+
+	res = lzip_decompress(stream->input, length, 0, 0, stream->output,
+				output->length, 0, &out_pos);
+	if (res < 0) {
+		ERROR("LZIP error code %d\n", res);
+		return -EIO;
+	}
+	bytes = out_pos;
+	data = squashfs_first_page(output);
+	buff = stream->output;
+	while (data) {
+		if (bytes <= PAGE_SIZE) {
+			memcpy(data, buff, bytes);
+			break;
+		}
+		memcpy(data, buff, PAGE_SIZE);
+		buff += PAGE_SIZE;
+		bytes -= PAGE_SIZE;
+		data = squashfs_next_page(output);
+	}
+	squashfs_finish_page(output);
+
+	return out_pos;
+}
+
+
+const struct squashfs_decompressor squashfs_lzip_comp_ops = {
+	.init = lzip_init,
+	.free = lzip_free,
+	.decompress = lzip_uncompress,
+	.id = LZIP_COMPRESSION,
+	.name = "lzip",
+	.supported = 1
+};
diff -urdN linux-5.16.11/fs/squashfs/squashfs_fs.h linux-5.16.11.new/fs/squashfs/squashfs_fs.h
--- linux-5.16.11/fs/squashfs/squashfs_fs.h	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/fs/squashfs/squashfs_fs.h	2022-02-28 22:10:45.790400069 +0100
@@ -236,6 +236,7 @@
 #define XZ_COMPRESSION		4
 #define LZ4_COMPRESSION		5
 #define ZSTD_COMPRESSION	6
+#define LZIP_COMPRESSION	7
 
 struct squashfs_super_block {
 	__le32			s_magic;
diff -urdN linux-5.16.11/include/linux/decompress/lunzip.h linux-5.16.11.new/include/linux/decompress/lunzip.h
--- linux-5.16.11/include/linux/decompress/lunzip.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/include/linux/decompress/lunzip.h	2022-02-28 22:10:45.790400069 +0100
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LINUX_DECOMPRESS_LUNZIP_H
+#define LINUX_DECOMPRESS_LUNZIP_H
+
+int lunzip(unsigned char *inbuf, long in_len,
+	   long (*fill)(void*, unsigned long),
+	   long (*flush)(void*, unsigned long),
+	   unsigned char *outbuf,
+	   long *in_posp,
+	   void (*error)(char *x));
+#endif
diff -urdN linux-5.16.11/include/linux/lzip.h linux-5.16.11.new/include/linux/lzip.h
--- linux-5.16.11/include/linux/lzip.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/include/linux/lzip.h	2022-02-28 23:01:36.770430310 +0100
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LZIP_H__
+#define __LZIP_H__
+/*
+ * LZIP decompressor
+ *
+ * Copyright (C) 2016-2022 Antonio Diaz Diaz.
+ */
+
+/* Return values (< 0 = Error) */
+enum {
+	LZIP_OOM_INBUF     = -1,
+	LZIP_HEADER1_EOF   = -2,
+	LZIP_HEADER2_EOF   = -3,
+	LZIP_BAD_MAGIC1    = -4,
+	LZIP_BAD_MAGIC2    = -5,
+	LZIP_BAD_VERSION   = -6,
+	LZIP_BAD_DICT_SIZE = -7,
+	LZIP_OOM_OUTBUF    = -8,
+	LZIP_WRITE_ERROR   = -9,
+	LZIP_BAD_DATA      = -10,
+	LZIP_DATA_EOF      = -11,
+	LZIP_BAD_CRC       = -12
+};
+
+int lzip_decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp);
+
+/* inbuf    - input buffer. If null or in_len <= 0, fill must be non-null
+ * in_len   - len of pre-read data in inbuf if inbuf is non-null
+ * fill     - if non-null, function to fill inbuf when empty
+ * flush    - if non-null, function to write out outbuf when full
+ * outbuf   - output buffer. If null or out_size <= 0, flush must be non-null
+ * out_size - size of outbuf if outbuf is non-null
+ * in_posp  - if non-null, the number of bytes consumed will be returned here
+ * out_posp - if non-null, the number of bytes produced will be returned here
+ *
+ * fill will be called (repeatedly) to read data. in_len bytes will be read
+ * per call (or 16384 bytes per call if inbuf is null or in_len <= 0).
+ *
+ * If flush is null, outbuf must be large enough to buffer all the expected
+ * output. Else the flush function will be called to flush the output buffer
+ * at the appropriate time (stream dependent).
+ * If out_size > 0 but is not large enough to buffer all the expected output,
+ * it must be at least as large as the dictionary size of the data.
+ *
+ * inbuf and outbuf may overlap (in-place decompression).
+ */
+
+#endif
diff -urdN linux-5.16.11/init/Kconfig linux-5.16.11.new/init/Kconfig
--- linux-5.16.11/init/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/init/Kconfig	2022-02-28 22:44:38.850430221 +0100
@@ -207,6 +207,9 @@
 config HAVE_KERNEL_BZIP2
 	bool
 
+config HAVE_KERNEL_LZIP
+	bool
+
 config HAVE_KERNEL_LZMA
 	bool
 
@@ -228,7 +231,7 @@
 choice
 	prompt "Kernel compression mode"
 	default KERNEL_GZIP
-	depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_ZSTD || HAVE_KERNEL_UNCOMPRESSED
+	depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZIP || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 || HAVE_KERNEL_ZSTD || HAVE_KERNEL_UNCOMPRESSED
 	help
 	  The linux kernel is a kind of self-extracting executable.
 	  Several compression algorithms are available, which differ
@@ -264,6 +267,15 @@
 	  Bzip2 uses a large amount of memory. For modern kernels you
 	  will need at least 8MB RAM or more for booting.
 
+config KERNEL_LZIP
+	bool "Lzip"
+	depends on HAVE_KERNEL_LZIP
+	help
+	  Lzip's compression ratio is better than that of gzip and bzip2.
+	  Decompression speed is between gzip and bzip2. Compression can be
+	  as fast as gzip or slower than bzip2 depending on compression level.
+	  Lzip can produce a kernel about a 16% smaller than gzip.
+
 config KERNEL_LZMA
 	bool "LZMA"
 	depends on HAVE_KERNEL_LZMA
@@ -2247,7 +2259,7 @@
 
 	  Please note that the tool used to load modules needs to support the
 	  corresponding algorithm. module-init-tools MAY support gzip, and kmod
-	  MAY support gzip, xz and zstd.
+	  MAY support gzip, lzip, xz and zstd.
 
 	  Your build system needs to provide the appropriate compression tool
 	  to compress the modules.
@@ -2266,6 +2278,12 @@
 	  Compress modules with GZIP. The installed modules are suffixed
 	  with .ko.gz.
 
+config MODULE_COMPRESS_LZIP
+	bool "LZIP"
+	help
+	  Compress modules with LZIP. The installed modules are suffixed
+	  with .ko.lz.
+
 config MODULE_COMPRESS_XZ
 	bool "XZ"
 	help
diff -urdN linux-5.16.11/init/do_mounts_rd.c linux-5.16.11.new/init/do_mounts_rd.c
--- linux-5.16.11/init/do_mounts_rd.c	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/init/do_mounts_rd.c	2022-02-28 22:10:45.790400069 +0100
@@ -49,6 +49,7 @@
  *	squashfs
  *	gzip
  *	bzip2
+ *	lzip
  *	lzma
  *	xz
  *	lzo
diff -urdN linux-5.16.11/lib/Kconfig linux-5.16.11.new/lib/Kconfig
--- linux-5.16.11/lib/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/lib/Kconfig	2022-02-28 22:10:45.790400069 +0100
@@ -311,6 +311,9 @@
 	help
 	 Enable s390x hardware support for zlib in the kernel.
 
+config LZIP_DECOMPRESS
+	tristate
+
 config LZO_COMPRESS
 	tristate
 
@@ -347,6 +350,10 @@
 config DECOMPRESS_BZIP2
 	tristate
 
+config DECOMPRESS_LZIP
+	select LZIP_DECOMPRESS
+	tristate
+
 config DECOMPRESS_LZMA
 	tristate
 
diff -urdN linux-5.16.11/lib/Makefile linux-5.16.11.new/lib/Makefile
--- linux-5.16.11/lib/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/lib/Makefile	2022-02-28 22:10:45.790400069 +0100
@@ -184,6 +184,7 @@
 obj-$(CONFIG_ZLIB_DFLTCC) += zlib_dfltcc/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
 obj-$(CONFIG_BCH) += bch.o
+obj-$(CONFIG_LZIP_DECOMPRESS) += lzip_decompress.o
 obj-$(CONFIG_LZO_COMPRESS) += lzo/
 obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
 obj-$(CONFIG_LZ4_COMPRESS) += lz4/
@@ -196,6 +197,7 @@
 
 lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
 lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+lib-$(CONFIG_DECOMPRESS_LZIP) += decompress_lunzip.o
 lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
 lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
 lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
diff -urdN linux-5.16.11/lib/decompress.c linux-5.16.11.new/lib/decompress.c
--- linux-5.16.11/lib/decompress.c	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/lib/decompress.c	2022-02-28 22:10:45.790400069 +0100
@@ -8,6 +8,7 @@
 #include <linux/decompress/generic.h>
 
 #include <linux/decompress/bunzip2.h>
+#include <linux/decompress/lunzip.h>
 #include <linux/decompress/unlzma.h>
 #include <linux/decompress/unxz.h>
 #include <linux/decompress/inflate.h>
@@ -26,6 +27,9 @@
 #ifndef CONFIG_DECOMPRESS_BZIP2
 # define bunzip2 NULL
 #endif
+#ifndef CONFIG_DECOMPRESS_LZIP
+# define lunzip NULL
+#endif
 #ifndef CONFIG_DECOMPRESS_LZMA
 # define unlzma NULL
 #endif
@@ -52,6 +56,7 @@
 	{ {0x1f, 0x8b}, "gzip", gunzip },
 	{ {0x1f, 0x9e}, "gzip", gunzip },
 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+	{ {0x4c, 0x5a}, "lzip", lunzip },
 	{ {0x5d, 0x00}, "lzma", unlzma },
 	{ {0xfd, 0x37}, "xz", unxz },
 	{ {0x89, 0x4c}, "lzo", unlzo },
diff -urdN linux-5.16.11/lib/decompress_lunzip.c linux-5.16.11.new/lib/decompress_lunzip.c
--- linux-5.16.11/lib/decompress_lunzip.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/lib/decompress_lunzip.c	2022-02-28 23:02:02.330425107 +0100
@@ -0,0 +1,100 @@
+/*
+ * Wrapper for decompressing LZIP-compressed kernel, initramfs, and initrd
+ *
+ * Copyright (C) 2016-2022 Antonio Diaz Diaz.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#ifdef STATIC
+#define PREBOOT
+#include "lzip_decompress.c"
+#else
+#include <linux/lzip.h>
+#include <linux/decompress/lunzip.h>
+#include <linux/decompress/mm.h>
+#endif
+
+STATIC int INIT __lunzip(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp,
+			void (*error)(char *x))
+{
+	const int retval = lzip_decompress(inbuf, in_len, fill, flush,
+					outbuf, out_size, in_posp, out_posp);
+	switch (retval) {
+	case 0: break;
+	case LZIP_OOM_INBUF:
+		error("Out of memory while allocating input buffer.");
+		break;
+	case LZIP_HEADER1_EOF:
+		error("File ends unexpectedly at member header.");
+		break;
+	case LZIP_HEADER2_EOF:
+		error("Truncated header in multimember file.");
+		break;
+	case LZIP_BAD_MAGIC1:
+		error("Bad magic number (file not in lzip format).");
+		break;
+	case LZIP_BAD_MAGIC2:
+		error("Corrupt header in multimember file.");
+		break;
+	case LZIP_BAD_VERSION:
+		error("Version of lzip member format not supported.");
+		break;
+	case LZIP_BAD_DICT_SIZE:
+		error("Invalid dictionary size in member header.");
+		break;
+	case LZIP_OOM_OUTBUF:
+		error("Out of memory while allocating output buffer.");
+		break;
+	case LZIP_WRITE_ERROR:
+		error("Write error.");
+		break;
+	case LZIP_BAD_DATA:
+		error("LZIP-compressed data is corrupt.");
+		break;
+	case LZIP_DATA_EOF:
+		error("LZIP-compressed data ends unexpectedly.");
+		break;
+	case LZIP_BAD_CRC:
+		error("CRC mismatch in LZIP-compressed data.");
+		break;
+	default:
+		error("Bug in the LZIP decompressor.");
+	}
+	return retval;
+}
+
+#ifndef PREBOOT
+/* decompress_fn (see include/linux/decompress/generic.h) should have an
+ * out_size argument to prevent overflowing outbuf in case of corruption
+ * of the compressed data.
+ */
+STATIC int INIT lunzip(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf,
+			long *in_posp,
+			void (*error)(char *x))
+{
+	return __lunzip(inbuf, in_len, fill, flush, outbuf, LONG_MAX,
+			in_posp, 0, error);
+}
+#else
+STATIC int INIT __decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp,
+			void (*error)(char *x))
+{
+/* Some archs pass out_size = 0 (to mean unlimited size), which is unsafe
+ * in case of corruption of the compressed data.
+ */
+	return __lunzip(inbuf, in_len - 4, fill, flush, outbuf,
+			out_size ? out_size : LONG_MAX, in_posp, 0, error);
+}
+#endif
diff -urdN linux-5.16.11/lib/lzip_decompress.c linux-5.16.11.new/lib/lzip_decompress.c
--- linux-5.16.11/lib/lzip_decompress.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-5.16.11.new/lib/lzip_decompress.c	2022-02-28 23:02:22.360432092 +0100
@@ -0,0 +1,873 @@
+/*
+ * LZIP decompressor
+ *
+ * Copyright (C) 2016-2022 Antonio Diaz Diaz.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+#include <linux/module.h>
+#include <linux/lzip.h>
+#include <linux/decompress/mm.h>
+
+/*
+ * STATIC_RW_DATA is used in the pre-boot environment on some architectures.
+ * See include/linux/decompress/mm.h for details.
+ */
+#ifndef STATIC_RW_DATA
+#define STATIC_RW_DATA static
+#endif
+
+typedef int State;
+
+enum { states = 12 };
+
+static inline bool St_is_char(const State st) { return st < 7; }
+
+static inline State St_set_char(const State st)
+{
+	STATIC_RW_DATA const State next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
+	return next[st];
+}
+
+static inline State St_set_match(const State st)
+{
+	return ((st < 7) ? 7 : 10);
+}
+
+static inline State St_set_rep(const State st)
+{
+	return ((st < 7) ? 8 : 11);
+}
+
+static inline State St_set_short_rep(const State st)
+{
+	return ((st < 7) ? 9 : 11);
+}
+
+
+enum {
+	min_dictionary_bits = 12,
+	min_dictionary_size = 1 << min_dictionary_bits,	/* >= modeled_distances */
+	max_dictionary_bits = 29,
+	max_dictionary_size = 1 << max_dictionary_bits,
+	literal_context_bits = 3,
+	pos_state_bits = 2,
+	pos_states = 1 << pos_state_bits,
+	pos_state_mask = pos_states - 1,
+
+	len_states = 4,
+	dis_slot_bits = 6,
+	start_dis_model = 4,
+	end_dis_model = 14,
+	modeled_distances = 1 << (end_dis_model / 2),	/* 128 */
+	dis_align_bits = 4,
+	dis_align_size = 1 << dis_align_bits,
+
+	len_low_bits = 3,
+	len_mid_bits = 3,
+	len_high_bits = 8,
+	len_low_symbols = 1 << len_low_bits,
+	len_mid_symbols = 1 << len_mid_bits,
+	len_high_symbols = 1 << len_high_bits,
+	max_len_symbols = len_low_symbols + len_mid_symbols + len_high_symbols,
+
+	min_match_len = 2,					/* must be 2 */
+	max_match_len = min_match_len + max_len_symbols - 1,	/* 273 */
+	min_match_len_limit = 5
+};
+
+static inline int get_len_state(const int len)
+{
+	return min(len - min_match_len, len_states - 1);
+}
+
+static inline int get_lit_state(const uint8_t prev_byte)
+{
+	return prev_byte >> (8 - literal_context_bits);
+}
+
+
+enum { bit_model_move_bits = 5,
+	bit_model_total_bits = 11,
+	bit_model_total = 1 << bit_model_total_bits
+};
+
+typedef int Bit_model;
+
+static inline void Bm_init(Bit_model * const probability)
+{
+	*probability = bit_model_total / 2;
+}
+
+static inline void Bm_array_init(Bit_model bm[], const int size)
+{
+	int i;
+
+	for (i = 0; i < size; ++i)
+		Bm_init(&bm[i]);
+}
+
+struct Len_model {
+	Bit_model choice1;
+	Bit_model choice2;
+	Bit_model bm_low[pos_states][len_low_symbols];
+	Bit_model bm_mid[pos_states][len_mid_symbols];
+	Bit_model bm_high[len_high_symbols];
+};
+
+static inline void Lm_init(struct Len_model * const lm)
+{
+	Bm_init(&lm->choice1);
+	Bm_init(&lm->choice2);
+	Bm_array_init(lm->bm_low[0], pos_states * len_low_symbols);
+	Bm_array_init(lm->bm_mid[0], pos_states * len_mid_symbols);
+	Bm_array_init(lm->bm_high, len_high_symbols);
+}
+
+
+/* Table of CRCs of all 8-bit messages. */
+STATIC_RW_DATA const uint32_t crc32[256] =
+  {
+  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
+
+
+static inline void CRC32_update_buf(uint32_t * const crc,
+					const uint8_t * const buffer,
+					const long size)
+{
+	long i;
+	uint32_t c = *crc;
+
+	for (i = 0; i < size; ++i)
+		c = crc32[(c^buffer[i])&0xFF] ^ (c >> 8);
+	*crc = c;
+}
+
+
+STATIC_RW_DATA const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */
+
+typedef uint8_t Lzip_header[6];		/* 0-3 magic bytes */
+					/*   4 version */
+					/*   5 coded dictionary size */
+enum { Lh_size = 6 };
+
+static inline bool Lh_verify_magic(const Lzip_header data)
+{
+	int i;
+
+	for (i = 0; i < 4; ++i)
+		if (data[i] != lzip_magic[i])
+			return false;
+	return true;
+}
+
+/* detect (truncated) header */
+static inline bool Lh_verify_prefix(const Lzip_header data, const int sz)
+{
+	int i;
+	for (i = 0; i < sz && i < 4; ++i)
+		if (data[i] != lzip_magic[i])
+			return false;
+	return (sz > 0);
+}
+
+/* detect corrupt header */
+static inline bool Lh_verify_corrupt(const Lzip_header data)
+{
+	int matches = 0;
+	int i;
+	for (i = 0; i < 4; ++i)
+		if (data[i] == lzip_magic[i])
+			++matches;
+	return (matches > 1 && matches < 4);
+}
+
+static inline bool Lh_verify_version(const Lzip_header data)
+{
+	return (data[4] == 1);
+}
+
+static inline unsigned Lh_get_dictionary_size(const Lzip_header data)
+{
+	unsigned sz = (1 << (data[5] & 0x1F));
+
+	if (sz > min_dictionary_size)
+		sz -= (sz / 16) * ((data[5] >> 5) & 7);
+	return sz;
+}
+
+
+typedef uint8_t Lzip_trailer[20];
+			/*  0-3  CRC32 of the uncompressed data */
+			/*  4-11 size of the uncompressed data */
+			/* 12-19 member size including header and trailer */
+enum { Lt_size = 20 };
+
+static inline unsigned Lt_get_data_crc(const Lzip_trailer data)
+{
+	unsigned tmp = 0;
+	int i;
+
+	for (i = 3; i >= 0; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+static inline unsigned long long Lt_get_data_size(const Lzip_trailer data)
+{
+	unsigned long long tmp = 0;
+	int i;
+
+	for (i = 11; i >= 4; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+static inline unsigned long long Lt_get_member_size(const Lzip_trailer data)
+{
+	unsigned long long tmp = 0;
+	int i;
+
+	for (i = 19; i >= 12; --i) {
+		tmp <<= 8;
+		tmp += data[i];
+	}
+	return tmp;
+}
+
+
+struct Range_decoder {
+	unsigned long long partial_member_pos;
+	uint8_t *buffer;	/* input buffer */
+	long buffer_size;
+	long pos;		/* current pos in buffer */
+	long stream_pos;	/* when reached, a new block must be read */
+	uint32_t code;
+	uint32_t range;
+	long (*fill)(void*, unsigned long);
+	bool at_stream_end;
+	bool buffer_given;
+};
+
+
+static bool Rd_read_block(struct Range_decoder * const rdec)
+{
+	if (!rdec->at_stream_end) {
+		rdec->stream_pos = rdec->fill ?
+			rdec->fill(rdec->buffer, rdec->buffer_size) : 0;
+		rdec->at_stream_end = (rdec->stream_pos < rdec->buffer_size);
+		rdec->partial_member_pos += rdec->pos;
+		rdec->pos = 0;
+	}
+	return rdec->pos < rdec->stream_pos;
+}
+
+
+static inline bool Rd_init(struct Range_decoder * const rdec,
+				uint8_t * const inbuf, const long in_len,
+				long (*fill)(void*, unsigned long))
+{
+	rdec->partial_member_pos = 0;
+	rdec->buffer_given = (inbuf && in_len > 0);
+	rdec->buffer_size = rdec->buffer_given ? in_len : 16384;
+	rdec->buffer = rdec->buffer_given ? inbuf : malloc(rdec->buffer_size);
+	if (!rdec->buffer)
+		return false;
+	rdec->pos = 0;
+	rdec->stream_pos = rdec->buffer_given ? in_len : 0;
+	rdec->code = 0;
+	rdec->range = 0xFFFFFFFFU;
+	rdec->fill = fill;
+	rdec->at_stream_end = false;
+	return true;
+}
+
+static inline void Rd_free(struct Range_decoder * const rdec)
+{
+	if (!rdec->buffer_given)
+		free(rdec->buffer);
+}
+
+static inline bool Rd_finished(struct Range_decoder * const rdec)
+{
+	return rdec->pos >= rdec->stream_pos && !Rd_read_block(rdec);
+}
+
+static inline unsigned long long
+Rd_member_position(const struct Range_decoder * const rdec)
+{
+	return rdec->partial_member_pos + rdec->pos;
+}
+
+static inline void Rd_reset_member_position(struct Range_decoder * const rdec)
+{
+	rdec->partial_member_pos = 0; rdec->partial_member_pos -= rdec->pos;
+}
+
+static inline uint8_t Rd_get_byte(struct Range_decoder * const rdec)
+{
+	/* 0xFF avoids decoder error if member is truncated at EOS marker */
+	if (Rd_finished(rdec))
+		return 0xFF;
+	return rdec->buffer[rdec->pos++];
+}
+
+static inline void Rd_load(struct Range_decoder * const rdec)
+{
+	int i;
+
+	rdec->code = 0;
+	for (i = 0; i < 5; ++i)
+		rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
+	rdec->range = 0xFFFFFFFFU;
+}
+
+static inline void Rd_normalize(struct Range_decoder * const rdec)
+{
+	if (rdec->range <= 0x00FFFFFFU) {
+		rdec->range <<= 8;
+		rdec->code = (rdec->code << 8) | Rd_get_byte(rdec);
+	}
+}
+
+static inline unsigned Rd_decode(struct Range_decoder * const rdec,
+				const int num_bits)
+{
+	unsigned symbol = 0;
+	int i;
+
+	for (i = num_bits; i > 0; --i) {
+		bool bit;
+
+		Rd_normalize(rdec);
+		rdec->range >>= 1;
+		/* symbol <<= 1; */
+		/* if(rdec->code >= rdec->range) { rdec->code -= rdec->range; symbol |= 1; } */
+		bit = (rdec->code >= rdec->range);
+		symbol <<= 1; symbol += bit;
+		rdec->code -= rdec->range & (0U - bit);
+	}
+	return symbol;
+}
+
+static inline unsigned Rd_decode_bit(struct Range_decoder * const rdec,
+					Bit_model * const probability)
+{
+	uint32_t bound;
+
+	Rd_normalize(rdec);
+	bound = (rdec->range >> bit_model_total_bits) * *probability;
+	if (rdec->code < bound) {
+		rdec->range = bound;
+		*probability += (bit_model_total - *probability) >> bit_model_move_bits;
+		return 0;
+	} else {
+		rdec->range -= bound;
+		rdec->code -= bound;
+		*probability -= *probability >> bit_model_move_bits;
+		return 1;
+	}
+}
+
+static inline unsigned Rd_decode_tree3(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 2 | Rd_decode_bit(rdec, &bm[1]);
+
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 7;
+}
+
+static inline unsigned Rd_decode_tree6(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 2 | Rd_decode_bit(rdec, &bm[1]);
+
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 0x3F;
+}
+
+static inline unsigned Rd_decode_tree8(struct Range_decoder * const rdec,
+					Bit_model bm[])
+{
+	unsigned symbol = 1;
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		symbol = (symbol << 1) | Rd_decode_bit(rdec, &bm[symbol]);
+	return symbol & 0xFF;
+}
+
+static inline unsigned
+Rd_decode_tree_reversed(struct Range_decoder * const rdec,
+			Bit_model bm[], const int num_bits)
+{
+	unsigned model = 1;
+	unsigned symbol = 0;
+	int i;
+
+	for (i = 0; i < num_bits; ++i) {
+		const unsigned bit = Rd_decode_bit(rdec, &bm[model]);
+
+		model <<= 1; model += bit;
+		symbol |= (bit << i);
+	}
+	return symbol;
+}
+
+static inline unsigned
+Rd_decode_tree_reversed4(struct Range_decoder * const rdec, Bit_model bm[])
+{
+	unsigned symbol = Rd_decode_bit(rdec, &bm[1]);
+
+	symbol += Rd_decode_bit(rdec, &bm[2+symbol]) << 1;
+	symbol += Rd_decode_bit(rdec, &bm[4+symbol]) << 2;
+	symbol += Rd_decode_bit(rdec, &bm[8+symbol]) << 3;
+	return symbol;
+}
+
+static inline unsigned Rd_decode_matched(struct Range_decoder * const rdec,
+					Bit_model bm[], unsigned match_byte)
+{
+	unsigned symbol = 1;
+	unsigned mask = 0x100;
+
+	while (true) {
+		const unsigned match_bit = (match_byte <<= 1) & mask;
+		const unsigned bit = Rd_decode_bit(rdec, &bm[symbol+match_bit+mask]);
+
+		symbol <<= 1; symbol += bit;
+		if (symbol > 0xFF)
+			return symbol & 0xFF;
+		mask &= ~(match_bit ^ (bit << 8));	/* if( match_bit != bit ) mask = 0; */
+	}
+}
+
+static inline unsigned Rd_decode_len(struct Range_decoder * const rdec,
+						struct Len_model * const lm,
+						const int pos_state)
+{
+	if (Rd_decode_bit(rdec, &lm->choice1) == 0)
+		return Rd_decode_tree3(rdec, lm->bm_low[pos_state]);
+	if (Rd_decode_bit(rdec, &lm->choice2) == 0)
+		return len_low_symbols +
+			Rd_decode_tree3(rdec, lm->bm_mid[pos_state]);
+	return len_low_symbols + len_mid_symbols +
+		Rd_decode_tree8(rdec, lm->bm_high);
+}
+
+
+struct LZ_decoder {
+	unsigned long long partial_data_pos;
+	struct Range_decoder *rdec;
+	/* Don't move bm_* to LZd_decode_member; makes frame too large. */
+	Bit_model bm_literal[1 << literal_context_bits][0x300];
+	Bit_model bm_match[states][pos_states];
+	Bit_model bm_rep[states];
+	Bit_model bm_rep0[states];
+	Bit_model bm_rep1[states];
+	Bit_model bm_rep2[states];
+	Bit_model bm_len[states][pos_states];
+	Bit_model bm_dis_slot[len_states][1 << dis_slot_bits];
+	Bit_model bm_dis[modeled_distances-end_dis_model+1];
+	Bit_model bm_align[dis_align_size];
+	struct Len_model match_len_model;
+	struct Len_model rep_len_model;
+
+	unsigned long buffer_size;
+	unsigned dictionary_size;
+	uint8_t *buffer;	/* output buffer */
+	unsigned long pos;	/* current pos in buffer */
+	unsigned long stream_pos;	/* first byte not yet written to file */
+	uint32_t crc;
+	long (*flush)(void*, unsigned long);
+	bool pos_wrapped;
+	bool buffer_given;
+	bool write_error;
+};
+
+static void LZd_flush_data(struct LZ_decoder * const d)
+{
+	if (d->pos > d->stream_pos) {
+		const long size = d->pos - d->stream_pos;
+
+		CRC32_update_buf(&d->crc, d->buffer + d->stream_pos, size);
+		if ((d->flush &&
+		     d->flush(d->buffer + d->stream_pos, size) != size) ||
+		    (!d->flush && d->pos_wrapped))
+			d->write_error = true;
+		if (d->pos >= d->buffer_size) {
+			d->partial_data_pos += d->pos;
+			d->pos = 0;
+			d->pos_wrapped = true;
+		}
+		d->stream_pos = d->pos;
+	}
+}
+
+static inline uint8_t LZd_peek_prev(const struct LZ_decoder * const d)
+{
+	if (d->pos > 0)
+		return d->buffer[d->pos-1];
+	if (d->pos_wrapped)
+		return d->buffer[d->buffer_size-1];
+	return 0;			/* prev_byte of first byte */
+}
+
+static inline uint8_t LZd_peek(const struct LZ_decoder * const d,
+				const unsigned distance)
+{
+	const unsigned long i = ((d->pos > distance) ? 0 : d->buffer_size) +
+				d->pos - distance - 1;
+	return d->buffer[i];
+}
+
+static inline void LZd_put_byte(struct LZ_decoder * const d, const uint8_t b)
+{
+	d->buffer[d->pos] = b;
+	if (++d->pos >= d->buffer_size)
+		LZd_flush_data(d);
+}
+
+static inline void LZd_copy_block(struct LZ_decoder * const d,
+				const unsigned distance, unsigned len)
+{
+	unsigned long lpos = d->pos, i = lpos - distance - 1;
+	bool fast, fast2;
+
+	if (lpos > distance) {
+		fast = (len < d->buffer_size - lpos);
+		fast2 = (fast && len <= lpos - i);
+	} else {
+		i += d->buffer_size;
+		fast = (len < d->buffer_size - i);	/* (i == pos) may happen */
+		fast2 = (fast && len <= i - lpos);
+	}
+	if (fast) {				/* no wrap */
+		d->pos += len;
+		if (fast2)			/* no wrap, no overlap */
+			memcpy(d->buffer + lpos, d->buffer + i, len);
+		else
+			for (; len > 0; --len)
+				d->buffer[lpos++] = d->buffer[i++];
+	} else
+		for (; len > 0; --len) {
+			d->buffer[d->pos] = d->buffer[i];
+			if (++d->pos >= d->buffer_size)
+				LZd_flush_data(d);
+			if (++i >= d->buffer_size)
+				i = 0;
+		}
+}
+
+static inline bool LZd_init(struct LZ_decoder * const d,
+			struct Range_decoder * const rde,
+			const unsigned dict_size, uint8_t * const outbuf,
+			long out_size, long (*flush)(void*, unsigned long))
+{
+	d->partial_data_pos = 0;
+	d->rdec = rde;
+	Bm_array_init(d->bm_literal[0], (1 << literal_context_bits) * 0x300);
+	Bm_array_init(d->bm_match[0], states * pos_states);
+	Bm_array_init(d->bm_rep, states);
+	Bm_array_init(d->bm_rep0, states);
+	Bm_array_init(d->bm_rep1, states);
+	Bm_array_init(d->bm_rep2, states);
+	Bm_array_init(d->bm_len[0], states * pos_states);
+	Bm_array_init(d->bm_dis_slot[0], len_states * (1 << dis_slot_bits));
+	Bm_array_init(d->bm_dis, modeled_distances - end_dis_model + 1);
+	Bm_array_init(d->bm_align, dis_align_size);
+	Lm_init(&d->match_len_model);
+	Lm_init(&d->rep_len_model);
+
+	d->buffer_given = (outbuf && out_size > 0);
+	d->buffer_size = d->buffer_given ? (unsigned long)out_size : dict_size;
+	d->dictionary_size = min_t(unsigned long, d->buffer_size, dict_size);
+	d->buffer = d->buffer_given ? outbuf : large_malloc(d->buffer_size);
+	if (!d->buffer)
+		return false;
+	d->pos = 0;
+	d->stream_pos = 0;
+	d->crc = 0xFFFFFFFFU;
+	d->flush = flush;
+	d->pos_wrapped = false;
+	d->write_error = false;
+	/* prev_byte of first byte; also for LZd_peek( 0 ) on corrupt file */
+	if (!d->buffer_given)		/* inbuf and outbuf may overlap */
+		d->buffer[d->buffer_size-1] = 0;
+	return true;
+}
+
+static inline void LZd_free(struct LZ_decoder * const d)
+{
+	if (!d->buffer_given)
+		large_free(d->buffer);
+}
+
+static inline unsigned LZd_crc(const struct LZ_decoder * const d)
+{
+	return d->crc ^ 0xFFFFFFFFU;
+}
+
+static inline unsigned long long
+LZd_data_position(const struct LZ_decoder * const d)
+{
+	return d->partial_data_pos + d->pos;
+}
+
+
+static bool LZd_verify_trailer(struct LZ_decoder * const d)
+{
+	Lzip_trailer trailer;
+	int i = 0;
+
+	while (i < Lt_size)
+		trailer[i++] = Rd_get_byte(d->rdec);
+
+	return (Lt_get_data_crc(trailer) == LZd_crc(d) &&
+		Lt_get_data_size(trailer) == LZd_data_position(d) &&
+		Lt_get_member_size(trailer) == Rd_member_position(d->rdec));
+}
+
+
+/* Return value: 0 = OK, < 0 = error (see include/linux/lzip.h). */
+static int LZd_decode_member(struct LZ_decoder * const d)
+{
+	struct Range_decoder * const rdec = d->rdec;
+	unsigned rep0 = 0;	/* rep[0-3] latest four distances */
+	unsigned rep1 = 0;	/* used for efficient coding of */
+	unsigned rep2 = 0;	/* repeated distances */
+	unsigned rep3 = 0;
+	State state = 0;
+
+	Rd_load(rdec);
+	while (!Rd_finished(rdec)) {
+		int len;
+		const int pos_state = LZd_data_position(d) & pos_state_mask;
+
+		if (Rd_decode_bit(rdec, &d->bm_match[state][pos_state]) == 0) {
+			/* literal byte */
+			Bit_model * const bm = d->bm_literal[get_lit_state(LZd_peek_prev(d))];
+
+			if (St_is_char(state)) {
+				state -= (state < 4) ? state : 3;
+				LZd_put_byte(d, Rd_decode_tree8(rdec, bm));
+			} else {
+				state -= (state < 10) ? 3 : 6;
+				LZd_put_byte(d, Rd_decode_matched(rdec, bm, LZd_peek(d, rep0)));
+			}
+		continue;
+		}
+		/* match or repeated match */
+		if (Rd_decode_bit(rdec, &d->bm_rep[state]) != 0) {
+			if (Rd_decode_bit(rdec, &d->bm_rep0[state]) == 0) {
+				if (Rd_decode_bit(rdec, &d->bm_len[state][pos_state]) == 0) {
+					state = St_set_short_rep(state);
+					LZd_put_byte(d, LZd_peek(d, rep0));
+					continue;
+				}
+			} else {
+				unsigned distance;
+
+				if (Rd_decode_bit(rdec, &d->bm_rep1[state]) == 0)
+					distance = rep1;
+				else {
+					if (Rd_decode_bit(rdec, &d->bm_rep2[state]) == 0)
+						distance = rep2;
+					else {
+						distance = rep3;
+						rep3 = rep2;
+					}
+					rep2 = rep1;
+				}
+				rep1 = rep0;
+				rep0 = distance;
+			}
+			state = St_set_rep(state);
+			len = min_match_len + Rd_decode_len(rdec, &d->rep_len_model, pos_state);
+		} else {			/* match */
+			unsigned distance;
+
+			len = min_match_len + Rd_decode_len(rdec, &d->match_len_model, pos_state);
+			distance = Rd_decode_tree6(rdec, d->bm_dis_slot[get_len_state(len)]);
+			if (distance >= start_dis_model) {
+				const unsigned dis_slot = distance;
+				const int direct_bits = (dis_slot >> 1) - 1;
+
+				distance = (2 | (dis_slot & 1)) << direct_bits;
+				if (dis_slot < end_dis_model)
+					distance += Rd_decode_tree_reversed(rdec,
+						d->bm_dis + (distance - dis_slot), direct_bits);
+				else {
+					distance +=
+					  Rd_decode(rdec, direct_bits - dis_align_bits) << dis_align_bits;
+					distance += Rd_decode_tree_reversed4(rdec, d->bm_align);
+					if (distance == 0xFFFFFFFFU) {	/* marker found */
+						Rd_normalize(rdec);
+						LZd_flush_data(d);
+						if (d->write_error)
+							return LZIP_WRITE_ERROR;
+						if (len == min_match_len) {	/* End Of Stream marker */
+							if (LZd_verify_trailer(d))
+								return 0;
+							else
+								return LZIP_BAD_CRC;
+						}
+						return LZIP_BAD_DATA;	/* unknown marker */
+					}
+				}
+			}
+			rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance;
+			state = St_set_match(state);
+			if (rep0 >= d->dictionary_size ||
+			   (rep0 >= d->pos && !d->pos_wrapped)) {
+				LZd_flush_data(d);
+				return LZIP_BAD_DATA;
+			}
+		}
+		LZd_copy_block(d, rep0, len);
+	}
+	LZd_flush_data(d);
+	return LZIP_DATA_EOF;
+}
+
+
+int lzip_decompress(unsigned char *inbuf, long in_len,
+			long (*fill)(void*, unsigned long),
+			long (*flush)(void*, unsigned long),
+			unsigned char *outbuf, long out_size,
+			long *in_posp, long *out_posp)
+{
+	unsigned char *outptr = outbuf;
+	struct Range_decoder rdec;
+	struct LZ_decoder *decoder = 0;
+	int retval = 0;
+	bool first_member;
+
+	if (in_posp)
+		*in_posp = 0;
+	if (out_posp)
+		*out_posp = 0;
+
+	if (!Rd_init(&rdec, inbuf, in_len, fill))
+		return LZIP_OOM_INBUF;
+
+	for (first_member = true;; first_member = false) {
+		long data_pos;
+		int size;
+		unsigned dictionary_size;
+		Lzip_header header;
+
+		Rd_reset_member_position(&rdec);
+		for (size = 0; size < Lh_size && !Rd_finished(&rdec); ++size)
+			header[size] = Rd_get_byte(&rdec);
+		if (Rd_finished(&rdec)) {	/* End Of File */
+			if (first_member)
+				retval = LZIP_HEADER1_EOF;
+			else if (Lh_verify_prefix(header, size))
+				retval = LZIP_HEADER2_EOF;
+			break;
+		}
+		if (!Lh_verify_magic(header)) {
+			if (first_member)
+				retval = LZIP_BAD_MAGIC1;
+			else if (Lh_verify_corrupt(header))
+				retval = LZIP_BAD_MAGIC2;
+			break;
+		}
+		if (!Lh_verify_version(header)) {
+			retval = LZIP_BAD_VERSION;
+			break;
+		}
+		dictionary_size = Lh_get_dictionary_size(header);
+		if (dictionary_size < min_dictionary_size ||
+		    dictionary_size > max_dictionary_size) {
+			retval = LZIP_BAD_DICT_SIZE;
+			break;
+		}
+
+		if (!decoder)
+			decoder = malloc(sizeof *decoder);
+		if (!decoder || !LZd_init(decoder, &rdec, dictionary_size,
+					outptr, out_size, flush)) {
+			retval = LZIP_OOM_OUTBUF;
+			break;
+		}
+		retval = LZd_decode_member(decoder);
+		if (in_posp)
+			*in_posp += Rd_member_position(&rdec);
+		data_pos = LZd_data_position(decoder);
+		if (outptr)
+			outptr += data_pos;
+		if (out_posp)
+			*out_posp += data_pos;
+		if (out_size > 0)
+			out_size -= data_pos;
+		LZd_free(decoder);
+		if (retval != 0)
+			break;
+	}
+	if (decoder)
+		free(decoder);
+	Rd_free(&rdec);
+	return retval;
+}
+
+#ifndef STATIC
+EXPORT_SYMBOL_GPL(lzip_decompress);
+#endif
+MODULE_DESCRIPTION("LZIP Decompressor");
+MODULE_AUTHOR("Antonio Diaz Diaz <antonio@gnu.org>");
+MODULE_LICENSE("GPL");
diff -urdN linux-5.16.11/scripts/Makefile.lib linux-5.16.11.new/scripts/Makefile.lib
--- linux-5.16.11/scripts/Makefile.lib	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/Makefile.lib	2022-02-28 22:10:45.800401973 +0100
@@ -397,6 +397,18 @@
 quiet_cmd_bzip2 = BZIP2   $@
       cmd_bzip2 = { cat $(real-prereqs) | $(KBZIP2) -9; $(size_append); } > $@
 
+# Lzip
+# ---------------------------------------------------------------------------
+# The .lz format has the uncompressed size available at the end of the
+# file, but at offset (member_size - 16). So we append a gzip-style size.
+# Use klzip to compress the kernel image and lzip to compress other things.
+
+quiet_cmd_klzip = LZIP    $@
+      cmd_klzip = { cat $(real-prereqs) | $(KLZIP) -9; $(size_append); } > $@
+
+quiet_cmd_lzip = LZIP    $@
+      cmd_lzip = cat $(real-prereqs) | $(KLZIP) -9 > $@
+
 # Lzma
 # ---------------------------------------------------------------------------
 
diff -urdN linux-5.16.11/scripts/Makefile.modinst linux-5.16.11.new/scripts/Makefile.modinst
--- linux-5.16.11/scripts/Makefile.modinst	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/Makefile.modinst	2022-02-28 22:29:45.920430307 +0100
@@ -20,6 +20,7 @@
 
 suffix-y				:=
 suffix-$(CONFIG_MODULE_COMPRESS_GZIP)	:= .gz
+suffix-$(CONFIG_MODULE_COMPRESS_LZIP)	:= .lz
 suffix-$(CONFIG_MODULE_COMPRESS_XZ)	:= .xz
 suffix-$(CONFIG_MODULE_COMPRESS_ZSTD)	:= .zst
 
@@ -94,6 +95,8 @@
 #
 quiet_cmd_gzip = GZIP    $@
       cmd_gzip = $(KGZIP) -n -f $<
+quiet_cmd_lzip = LZIP    $@
+      cmd_lzip = $(KLZIP) -f $<
 quiet_cmd_xz = XZ      $@
       cmd_xz = $(XZ) --lzma2=dict=2MiB -f $<
 quiet_cmd_zstd = ZSTD    $@
@@ -102,6 +105,9 @@
 $(dst)/%.ko.gz: $(dst)/%.ko FORCE
 	$(call cmd,gzip)
 
+$(dst)/%.ko.lz: $(dst)/%.ko FORCE
+	$(call cmd,lzip)
+
 $(dst)/%.ko.xz: $(dst)/%.ko FORCE
 	$(call cmd,xz)
 
diff -urdN linux-5.16.11/scripts/extract-ikconfig linux-5.16.11.new/scripts/extract-ikconfig
--- linux-5.16.11/scripts/extract-ikconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/extract-ikconfig	2022-02-28 22:10:45.800401973 +0100
@@ -59,6 +59,7 @@
 try_decompress '\037\213\010' xy    gunzip
 try_decompress '\3757zXZ\000' abcde unxz
 try_decompress 'BZh'          xy    bunzip2
+try_decompress 'LZIP'         xyz   'lzip -d'
 try_decompress '\135\0\0\0'   xxx   unlzma
 try_decompress '\211\114\132' xy    'lzop -d'
 try_decompress '\002\041\114\030' xyy 'lz4 -d -l'
diff -urdN linux-5.16.11/scripts/extract-vmlinux linux-5.16.11.new/scripts/extract-vmlinux
--- linux-5.16.11/scripts/extract-vmlinux	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/extract-vmlinux	2022-02-28 22:10:45.800401973 +0100
@@ -52,6 +52,7 @@
 try_decompress '\037\213\010' xy    gunzip
 try_decompress '\3757zXZ\000' abcde unxz
 try_decompress 'BZh'          xy    bunzip2
+try_decompress 'LZIP'         xyz   'lzip -d'
 try_decompress '\135\0\0\0'   xxx   unlzma
 try_decompress '\211\114\132' xy    'lzop -d'
 try_decompress '\002!L\030'   xxx   'lz4 -d'
diff -urdN linux-5.16.11/scripts/package/buildtar linux-5.16.11.new/scripts/package/buildtar
--- linux-5.16.11/scripts/package/buildtar	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/package/buildtar	2022-02-28 22:10:45.800401973 +0100
@@ -35,6 +35,10 @@
 		opts="-I ${KBZIP2}"
 		tarball=${tarball}.bz2
 		;;
+	tarlz-pkg)
+		opts="-I ${KLZIP}"
+		tarball=${tarball}.lz
+		;;
 	tarxz-pkg)
 		opts="-I ${XZ}"
 		tarball=${tarball}.xz
diff -urdN linux-5.16.11/scripts/patch-kernel linux-5.16.11.new/scripts/patch-kernel
--- linux-5.16.11/scripts/patch-kernel	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/scripts/patch-kernel	2022-02-28 22:10:45.800401973 +0100
@@ -117,6 +117,10 @@
 		ext=".bz2"
 		name="bzip2"
 		uncomp="bunzip2 -dc"
+  elif [ -r ${filebase}.lz ]; then
+		ext=".lz"
+		name="lzip"
+		uncomp="lzip -dc"
   elif [ -r ${filebase}.xz ]; then
                 ext=".xz"
                 name="xz"
diff -urdN linux-5.16.11/tools/testing/selftests/gen_kselftest_tar.sh linux-5.16.11.new/tools/testing/selftests/gen_kselftest_tar.sh
--- linux-5.16.11/tools/testing/selftests/gen_kselftest_tar.sh	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/tools/testing/selftests/gen_kselftest_tar.sh	2022-02-28 23:52:00.350458667 +0100
@@ -27,6 +27,10 @@
 				copts="cvjf"
 				ext=".tar.bz2"
 				;;
+			tarlz)
+				copts="-cv --lzip -f"
+				ext=".tar.lz"
+				;;
 			tarxz)
 				copts="cvJf"
 				ext=".tar.xz"
diff -urdN linux-5.16.11/usr/Kconfig linux-5.16.11.new/usr/Kconfig
--- linux-5.16.11/usr/Kconfig	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/usr/Kconfig	2022-03-01 00:01:32.160430303 +0100
@@ -68,6 +68,14 @@
 	  Support loading of a bzip2 encoded initial ramdisk or cpio buffer
 	  If unsure, say N.
 
+config RD_LZIP
+	bool "Support initial ramdisk/ramfs compressed using lzip"
+	default y
+	select DECOMPRESS_LZIP
+	help
+	  Support loading of a lzip encoded initial ramdisk or cpio buffer.
+	  If unsure, say N.
+
 config RD_LZMA
 	bool "Support initial ramdisk/ramfs compressed using LZMA"
 	default y
@@ -155,6 +163,18 @@
 	  If you choose this, keep in mind that you need to have the bzip2 tool
 	  available to be able to compress the initram.
 
+config INITRAMFS_COMPRESSION_LZIP
+	bool "Lzip"
+	depends on RD_LZIP
+	help
+	  Lzip's compression ratio is better than that of gzip and bzip2.
+	  Decompression speed is between gzip and bzip2. Compression can be
+	  as fast as gzip or slower than bzip2 depending on compression level.
+	  Lzip can produce a initramfs about a 16% smaller than gzip.
+
+	  If you choose this, keep in mind that you need to have the lzip tool
+	  available to be able to compress the initram.
+
 config INITRAMFS_COMPRESSION_LZMA
 	bool "LZMA"
 	depends on RD_LZMA
diff -urdN linux-5.16.11/usr/Makefile linux-5.16.11.new/usr/Makefile
--- linux-5.16.11/usr/Makefile	2022-02-24 00:42:52.000000000 +0100
+++ linux-5.16.11.new/usr/Makefile	2022-02-28 22:10:45.800401973 +0100
@@ -11,6 +11,7 @@
 compress-y					:= shipped
 compress-$(CONFIG_INITRAMFS_COMPRESSION_GZIP)	:= gzip
 compress-$(CONFIG_INITRAMFS_COMPRESSION_BZIP2)	:= bzip2
+compress-$(CONFIG_INITRAMFS_COMPRESSION_LZIP)	:= lzip
 compress-$(CONFIG_INITRAMFS_COMPRESSION_LZMA)	:= lzma
 compress-$(CONFIG_INITRAMFS_COMPRESSION_XZ)	:= xzmisc
 compress-$(CONFIG_INITRAMFS_COMPRESSION_LZO)	:= lzo
